// Panel.cpp

#include "StdAfx.h"

#include "Common/String/StringConvert.h"

//A.M. Maybe App.h variable can be removed
#include "App.h"
#include "Common/FileSystem/FileFind.h"
#include "Common/FileSystem/Wildcard.h"

#include "Panel.h"

#include "FileManager/Windows.h"
#include "ListViewDialog.h"
#include "CopyDialog.h"


static const UINT_PTR kTimerID = 1;
static const UINT kTimerElapse = 1000;

static DWORD kStyles[4] = { LVS_ICON, LVS_SMALLICON, LVS_LIST, LVS_REPORT };

using namespace Common;

void CPanel::Release()
{
	// It's for unloading COM dll's: don't change it.
	m_directory.CloseOpenFolders();
	_sevenZipContextMenu.Release();
	_systemContextMenu.Release();
}

CPanel::~CPanel()
{
	
}


static LPCTSTR kClassName = _T("7-Zip::Panel");

void CPanel::RefreshTitle(bool always)
{
	m_pApp->RefreshTitle(always);
}

HWND CPanel::Create(HWND mainWindow, HWND parentWindow, HWND statusWnd, UINT id, //int index,
					const CString &currentFolderPrefix,
					const CString &arcFormat,
					CMainWnd* app, CAppState* appState,
					bool &archiveIsOpened, bool &encrypted)
{
	_mainWindow = mainWindow;
	_processTimer = true;
	_processNotify = true;

	m_pApp = app;
	m_directory.SetThreadPool(app->GetUIThreadPool());

	_appState = appState;
	_baseID = id;
	_comboBoxID = _baseID + 3;

	_statusBar.Attach(statusWnd);

	CString cfp = currentFolderPrefix;

	if (!currentFolderPrefix.IsEmpty())
		if (currentFolderPrefix[0] == _T('.'))
			if (!Common::FileSystem::GetFullPathName(currentFolderPrefix, cfp))
			{
				cfp = currentFolderPrefix;
			}
	if (S_OK != m_directory.BindToPath(cfp, arcFormat, archiveIsOpened, encrypted))
	{
		return NULL;
	}
	HWND result = baseClass::Create(parentWindow, rcDefault, NULL, WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS | WS_CLIPCHILDREN, WS_EX_CLIENTEDGE, id);
	//Create function calls RefreshListCtrl() as well
	//RefreshListCtrl();
	return result;
}


LRESULT CMyListView::OnKeyDown(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL &bHandled)
{
	bool alt = (::GetKeyState(VK_MENU) & 0x8000) != 0;
	bool ctrl = (::GetKeyState(VK_CONTROL) & 0x8000) != 0;
	bool shift = (::GetKeyState(VK_SHIFT) & 0x8000) != 0;
	switch(wParam)
	{
		case VK_NEXT:
		{
			if (ctrl && !alt && !shift)
			{
				_panel->OpenFocusedItemAsInternal();
				bHandled = TRUE;
				return 0;
			}
			break;
		}
		case VK_PRIOR:
			if (ctrl && !alt && !shift)
			{
				_panel->OpenParentFolder();
				bHandled = TRUE;
				return 0;
			}
	}
	return 1;
}

LRESULT CMyListView::OnChar(UINT /*uMsg*/, WPARAM wParam, LPARAM lParam, BOOL & /*bHandled*/)
{
	UINT scanCode = (UINT)((lParam >> 16) & 0xFF);
	//bool extended = ((lParam & 0x1000000) != 0);
	UINT virtualKey = MapVirtualKey(scanCode, 1);
	if (virtualKey == VK_MULTIPLY || virtualKey == VK_ADD ||
			virtualKey == VK_SUBTRACT)
	{
		return 0;
	}
	//TODO: No need to check for extended in this case for if it always checks for '/'
	if (//(wParam == '/' && extended) || 
			wParam == '\\' || wParam == '/')
	{
		_panel->OpenDrivesFolder();
		return 0;
	}
	return 1;
}
LRESULT CMyListView::OnSysChar(UINT /*uMsg*/, WPARAM wParam, LPARAM lParam, BOOL & /*bHandled*/)
{
	UINT scanCode = (UINT)(lParam >> 16) & 0xFF;
	UINT virtualKey = MapVirtualKey(scanCode, 1);
	if (virtualKey == VK_RETURN || virtualKey == VK_MULTIPLY ||
			virtualKey == VK_ADD || virtualKey == VK_SUBTRACT)
	{
		return 0;
	}
	return 1;
}

LRESULT CMyListView::OnSetFocus(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL & /*bHandled*/)
{
	_panel->_lastFocusedIsList = true;
	return 1;
}

LRESULT CMyComboBoxEdit::OnSysKeyDown(UINT /*uMsg*/, WPARAM wParam, LPARAM lParam, BOOL & /*bHandled*/)
{
	switch (wParam)
	{
		case VK_F1:
		case VK_F2:
		{
			// check ALT
			if ((lParam & (1 << 29)) == 0)
			{
				break;
			}
			bool alt = (::GetKeyState(VK_MENU) & 0x8000) != 0;
			bool ctrl = (::GetKeyState(VK_CONTROL) & 0x8000) != 0;
			bool shift = (::GetKeyState(VK_SHIFT) & 0x8000) != 0;
			if (alt && !ctrl && !shift)
			{
				_panel->m_pApp->SetFocusToPath(wParam == VK_F1 ? 0 : 1);
				return 0;
			}
			break;
		}
	}
	return 1;
}

LRESULT CMyComboBoxEdit::OnKeyDown(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL & /*bHandled*/)
{
	switch (wParam)
	{
		case VK_TAB:
			// SendMessage(hwndMain, WM_ENTER, 0, 0);
			_panel->SetFocusToList();
			return 0;
	}
	return 1;
}

LRESULT CMyComboBoxEdit::OnChar(UINT /*uMsg*/, WPARAM wParam, LPARAM lParam, BOOL & /*bHandled*/)
{
	switch (wParam)
	{
		case VK_TAB:
		case VK_ESCAPE:
			return 0;
	}
	return 1;
}


int CPanel::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
	m_directory.SetWindow(*this);
	_sortID = kpidName;
	_ascending = true;
	_lastFocusedIsList = true;

	DWORD style = WS_CHILD | WS_VISIBLE; //  | WS_BORDER ; // | LVS_SHAREIMAGELISTS; //  | LVS_SHOWSELALWAYS;;

	style |= LVS_SHAREIMAGELISTS;
	// style  |= LVS_AUTOARRANGE;
	style |= WS_CLIPCHILDREN;
	style |= WS_CLIPSIBLINGS;

	const UINT32 kNumListModes = sizeof(kStyles) / sizeof(kStyles[0]);
	if (_ListViewMode >= kNumListModes)
	{
		_ListViewMode = kNumListModes - 1;
	}

	style |= kStyles[_ListViewMode]
			 | WS_TABSTOP
			 | LVS_EDITLABELS;
	if (_mySelectMode)
	{
		style |= LVS_SINGLESEL;
	}

	DWORD exStyle(_exStyle);
	exStyle |= WS_EX_CLIENTEDGE;

	RECT rect;
	rect.left = 0;
	rect.top = 0;
	rect.right = 116;
	rect.bottom = 260;

	if (!_listView.Create(*this, rect, NULL, style, exStyle, (HMENU)(UINT_PTR)(_baseID + 1)))
	{
		return false;
	}

#ifndef UNDER_CE
	_listView.SetUnicodeFormat(true);
#endif

	_listView.SetWindowLongPtr(GWL_USERDATA, LONG_PTR(&_listView));
	_listView._panel = this;


	_listView.SetImageList(Common::FileSystem::GetSysImageList(true), LVSIL_SMALL);
	_listView.SetImageList(Common::FileSystem::GetSysImageList(false), LVSIL_NORMAL);

	// _exStyle |= LVS_EX_HEADERDRAGDROP;
	// DWORD extendedStyle = _listView.GetExtendedListViewStyle();
	// extendedStyle |= _exStyle;
	//  _listView.SetExtendedListViewStyle(extendedStyle);
	SetExtendedStyle();

	_listView.ShowWindow(SW_SHOW);
	_listView.InvalidateRect(NULL, true);
	_listView.UpdateWindow();

	// Ensure that the common control DLL is loaded.
	INITCOMMONCONTROLSEX icex;

	icex.dwSize = sizeof(INITCOMMONCONTROLSEX);
	icex.dwICC  = ICC_BAR_CLASSES;
	InitCommonControlsEx(&icex);

	TBBUTTON tbb [ ] =
	{
		// {0, 0, TBSTATE_ENABLED, BTNS_SEP, 0L, 0},
		{VIEW_PARENTFOLDER, kParentFolderID, TBSTATE_ENABLED, BTNS_BUTTON, 0L, 0},
		// {0, 0, TBSTATE_ENABLED, BTNS_SEP, 0L, 0},
		// {VIEW_NEWFOLDER, kCreateFolderID, TBSTATE_ENABLED, BTNS_BUTTON, 0L, 0},
	};

	icex.dwSize = sizeof(INITCOMMONCONTROLSEX);
	icex.dwICC  = ICC_COOL_CLASSES | ICC_BAR_CLASSES;
	InitCommonControlsEx(&icex);

	_headerReBar.Attach(::CreateWindowEx(WS_EX_TOOLWINDOW,
										 REBARCLASSNAME,
										 NULL, WS_VISIBLE | WS_BORDER | WS_CHILD |
										 WS_CLIPCHILDREN | WS_CLIPSIBLINGS
										 | CCS_NODIVIDER
										 // | CCS_NOPARENTALIGN
										 | CCS_TOP
										 | RBS_VARHEIGHT
										 | RBS_BANDBORDERS
										 , 0, 0, 0, 0, HWND(*this), NULL, _AtlBaseModule.GetModuleInstance(), NULL));

	DWORD toolbarStyle =  WS_CHILD | WS_VISIBLE ;
	if (_headerReBar)
	{
		toolbarStyle |= 0
						// | WS_CLIPCHILDREN
						// | WS_CLIPSIBLINGS

						| TBSTYLE_TOOLTIPS
						| CCS_NODIVIDER
						| CCS_NORESIZE
						| TBSTYLE_FLAT
						;
	}

	_headerToolBar.Attach(::CreateToolbarEx ((*this), toolbarStyle,
						  _baseID + 2, 11,
						  (HINSTANCE)HINST_COMMCTRL,
						  IDB_VIEW_SMALL_COLOR,
						  (LPCTBBUTTON)&tbb, sizeof(tbb) / sizeof(tbb[0]),
						  0, 0, 0, 0, sizeof (TBBUTTON)));

#ifndef UNDER_CE
	// Load ComboBoxEx class
	icex.dwSize = sizeof(INITCOMMONCONTROLSEX);
	icex.dwICC = ICC_USEREX_CLASSES;
	InitCommonControlsEx(&icex);
#endif

	RECT rcBox;
	rcBox.left = 0;
	rcBox.top = 0;
	rcBox.right = 100;
	rcBox.bottom = 500;

	_headerComboBox.Create(((_headerReBar == 0) ? HWND(*this) : _headerToolBar), rcBox, NULL,
						   WS_BORDER | WS_VISIBLE | WS_CHILD | CBS_DROPDOWN | CBS_AUTOHSCROLL,
						   0, (HMENU)(UINT_PTR)(_comboBoxID));
#ifndef UNDER_CE
	_headerComboBox.SetUnicodeFormat(true);

	_headerComboBox.SetImageList(Common::FileSystem::GetSysImageList(true));

	_headerComboBox.SetExtendedStyle(CBES_EX_PATHWORDBREAKPROC, CBES_EX_PATHWORDBREAKPROC);


	_comboBoxEdit._panel = this;

#endif

	if (_headerReBar)
	{
		REBARINFO     rbi;
		rbi.cbSize = sizeof(REBARINFO);  // Required when using this struct.
		rbi.fMask  = 0;
		rbi.himl   = (HIMAGELIST)NULL;
		_headerReBar.SetBarInfo(&rbi);

		// Send the TB_BUTTONSTRUCTSIZE message, which is required for
		// backward compatibility.
		// _headerToolBar.SendMessage(TB_BUTTONSTRUCTSIZE, (WPARAM)sizeof(TBBUTTON), 0);
		SIZE size;
		_headerToolBar.GetMaxSize(&size);

		REBARBANDINFO rbBand;
		rbBand.cbSize = sizeof(REBARBANDINFO);  // Required
		rbBand.fMask = RBBIM_STYLE | RBBIM_CHILD | RBBIM_CHILDSIZE | RBBIM_SIZE;
		rbBand.fStyle = RBBS_NOGRIPPER;
		rbBand.cxMinChild = size.cx;
		rbBand.cyMinChild = size.cy;
		rbBand.cyChild = size.cy;
		rbBand.cx = size.cx;
		rbBand.hwndChild  = _headerToolBar;
		_headerReBar.InsertBand(-1, &rbBand);

		RECT rc;
		::GetWindowRect(_headerComboBox, &rc);
		rbBand.cxMinChild = 30;
		rbBand.cyMinChild = rc.bottom - rc.top;
		rbBand.cx = 1000;
		rbBand.hwndChild  = _headerComboBox;
		_headerReBar.InsertBand(-1, &rbBand);
		// _headerReBar.MaximizeBand(1, false);
	}


	int sizes[] = {150, 250, 350, -1};
	_statusBar.SetParts(4, sizes);

	SetTimer(kTimerID, kTimerElapse);

	RefreshListCtrl();
	RefreshStatusBar();

	return 1;
}

void CPanel::OnDestroy()
{
	SaveListViewInfo();
	PostQuitMessage(0);
}

void CPanel::ChangeWindowSize(CSize &size)
{
	if ((HWND)*this == 0)
	{
		return;
	}
	int kHeaderSize;
	RECT rect;
	if (_headerReBar)
	{
		_headerReBar.GetWindowRect(&rect);
	}
	else
	{
		_headerToolBar.GetWindowRect(&rect);
	}

	kHeaderSize = rect.bottom - rect.top;

	int yListViewSize = max(size.cy - kHeaderSize, 0L);
	const LONG kStartXPos = 32;
	if (_headerReBar)
	{
	}
	else
	{
		_headerToolBar.MoveWindow(0, 0, size.cx, 0);
		_headerComboBox.MoveWindow(kStartXPos, 2,
								   max(size.cx - kStartXPos - 10, kStartXPos), 0);
	}
	_listView.MoveWindow(0, kHeaderSize, size.cx, yListViewSize);
}

void CPanel::OnSize(UINT nType, CSize size)
{
	if ((HWND)*this == 0)
	{
		return;
	}
	if (_headerReBar)
	{
		_headerReBar.MoveWindow(0, 0, size.cx, 0);
	}
	ChangeWindowSize(size);
}

LRESULT CPanel::OnOpenItemChanged(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM lParam, BOOL & /*bHandled*/)
{
	
	CSelectedState state;
	SaveSelectedState(state);

	LRESULT result = m_directory.OnOpenItemChanged(lParam);
	if (0 == result)
	{
		return 0;
	}
	RefreshListCtrl(state);
	return 1;
}


bool CPanel::OnNotifyReBar(LPNMHDR header, LRESULT & /* result */, BOOL &bHandled)
{
	switch(header->code)
	{
		case RBN_HEIGHTCHANGE:
		{
			CRect rect;
			GetWindowRect(&rect);
			ChangeWindowSize(rect.Size());
			return false;
		}
	}
	bHandled = FALSE;
	return false;
}

LRESULT CPanel::OnNotifyHandler(UINT /*uMsg*/, WPARAM wParam, LPARAM lParam, BOOL &bHandled)
{
	LPNMHDR pnmh = (LPNMHDR)lParam;
	int id = (int)wParam;
	return OnNotify(id, pnmh, bHandled);

}

LRESULT CPanel::OnNotify(int /*idCtrl*/, LPNMHDR pnmh,  BOOL &bHandled)
{
	if (!_processNotify || !m_directory.GetProcessNotify())
	{
		bHandled = FALSE;
		return 0;
	}
	LRESULT result(0);
	if (pnmh->hwndFrom == _headerComboBox)
	{
		return OnNotifyComboBox(pnmh, result, bHandled);
	}
	else if (pnmh->hwndFrom == _headerReBar)
	{
		return OnNotifyReBar(pnmh, result,  bHandled);
	}
	// if (header->hwndFrom == _listView)
	else if (pnmh->hwndFrom == _listView)
	{
		return OnNotifyList(pnmh, result, bHandled);
	}
	else if (::GetParent(pnmh->hwndFrom) == _listView &&
			 pnmh->code == NM_RCLICK)
	{
		return OnRightClick((MY_NMLISTVIEW_NMITEMACTIVATE*)pnmh, result, bHandled);
	}
	bHandled = FALSE;
	return result;
}



void CPanel::SetFocusToList()
{
	_listView.SetFocus();
}

void CPanel::SetFocusToLastRememberedItem()
{
	if (_lastFocusedIsList)
	{
		SetFocusToList();
	}
	else
	{
		_headerComboBox.SetFocus();
	}
}

void CPanel::SetListViewMode(UINT32 index)
{
	if (index >= 4)
	{
		return;
	}
	_ListViewMode = index;
	DWORD oldStyle = (DWORD)_listView.GetStyle();
	DWORD newStyle = kStyles[index];
	if ((oldStyle & LVS_TYPEMASK) != newStyle)
		//    _listView.SetStyle((oldStyle & ~LVS_TYPEMASK) | newStyle);
	{
		_listView.SetWindowLongPtr(GWL_STYLE, (oldStyle & ~LVS_TYPEMASK) | newStyle);
	}
	// RefreshListCtrlSaveFocused();
}

void CPanel::ChangeFlatMode()
{
	m_directory.ChangeFlatMode();
	RefreshListCtrlSaveFocused();
}


void CPanel::RefreshStatusBar()
{
	PostMessage(kRefreshStatusBar);
}

void CPanel::AddToArchive()
{
	std::vector<UINT32> indices;
	GetOperatedItemIndices(indices);
	m_directory.AddToArchive(indices);
}

void CPanel::ExtractArchives()
{
	if (m_directory.IsArchive())
	{
		//TODO: check if needed
		CopyItems(false, false);
		return;
	}
	std::vector<UINT32> indices;
	GetOperatedItemIndices(indices);
	m_directory.ExtractArchives(indices);
}



void CPanel::TestArchives()
{
	std::vector<UINT32> indices;
	GetOperatedIndicesSmart(indices);
	if (m_directory.TestArchives(indices))
		RefreshTitleAlways();
}



//moved DirectoryOperations.cpp/PanelOperations.cpp
void CPanel::RenameFile()
{
	int index = _listView.GetNextItem(-1, LVNI_FOCUSED);
	if (index >= 0)
	{
		_listView.EditLabel(index);
	}
}


//moved from DirectoryFolderChange.cpp/PanelFolderChange.cpp

void CPanel::SetBookmark(size_t index)
{
	_appState->FastFolders.SetString(index, m_directory.GetCurrentDirectory());
}

void CPanel::OpenBookmark(size_t index)
{
	m_directory.BindToPathAndRefresh(_appState->FastFolders.GetString(index));
	RefreshListCtrl();
}

void CPanel::OpenParentFolder()
{
	CStringVector selectedItems;
	CString seletedItem;
	m_directory.OpenParentFolder(seletedItem);
	RefreshListCtrl(seletedItem, -1, true, selectedItems);
	_listView.EnsureVisible(_listView.GetNextItem(-1, LVNI_FOCUSED), false);
	RefreshStatusBar();
}

void CPanel::OpenDrivesFolder()
{
	m_directory.OpenDrivesFolder();
	RefreshListCtrl();
}

void CPanel::LoadFullPathAndShow()
{
	//Directory now is always at consistent state
	//m_directory.LoadFullPath();
	_appState->FolderHistory.AddString(m_directory.GetCurrentDirectory());

	_headerComboBox.SetWindowText(m_directory.GetCurrentDirectory());

#ifndef UNDER_CE
	COMBOBOXEXITEM item;
	item.mask = 0;

	CString path = m_directory.GetCurrentDirectory();
	if (path.GetLength() >
#ifdef _WIN32
			3
#else
			1
#endif
			&& path[path.GetLength() - 1] == CHAR_PATH_SEPARATOR)
	{
		path.Delete(path.GetLength() - 1);
	}

	FileSystem::File::CFileInfo info;
	DWORD attrib = FILE_ATTRIBUTE_DIRECTORY;
	if (info.Find(path))
	{
		attrib = info.Attributes;
	}

	item.iImage = FileManager::FileSystem::GetRealIconIndex(path, attrib);

	if (item.iImage >= 0)
	{
		item.iSelectedImage = item.iImage;
		item.mask |= (CBEIF_IMAGE | CBEIF_SELECTEDIMAGE);
	}
	item.iItem = -1;
	_headerComboBox.SetItem(&item);
#endif

	RefreshTitle();
}

#ifndef UNDER_CE
LRESULT CPanel::OnNotifyComboBoxEnter(const CString &s)
{
	if (m_directory.BindToPathAndRefresh(String::GetUnicodeString(s)) == S_OK)
	{
		RefreshListCtrl();
		PostMessage(kSetFocusToListView);
		return TRUE;
	}
	return FALSE;
}

bool CPanel::OnNotifyComboBoxEndEdit(PNMCBEENDEDIT info, LRESULT &result)
{
	if (info->iWhy == CBENF_ESCAPE)
	{
		_headerComboBox.SetWindowText(m_directory.GetCurrentDirectory());
		PostMessage(kSetFocusToListView);
		result = FALSE;
		return true;
	}


	if (info->iWhy == CBENF_RETURN)
	{
		// When we use Edit control and press Enter.
		CString s;
		_headerComboBox.GetWindowText(s);
		result = OnNotifyComboBoxEnter(s);
		return true;
	}
	return false;
}
#endif

void CPanel::AddComboBoxItem(const CString &name, int iconIndex, int indent, bool addToList)
{
#ifdef UNDER_CE

	CString s;
	iconIndex = iconIndex;
	for (int i = 0; i < indent; i++)
	{
		s += _T("  ");
	}
	_headerComboBox.AddString(s + name);

#else

	COMBOBOXEXITEM item;
	item.mask = CBEIF_TEXT | CBEIF_INDENT;
	item.iSelectedImage = item.iImage = iconIndex;
	if (iconIndex >= 0)
	{
		item.mask |= (CBEIF_IMAGE | CBEIF_SELECTEDIMAGE);
	}
	item.iItem = -1;
	item.iIndent = indent;
	item.pszText = (LPTSTR)(LPCTSTR)name;
	_headerComboBox.InsertItem(&item);

#endif

	if (addToList)
	{
		ComboBoxPaths.push_back(name);
	}
}


bool CPanel::OnComboBoxCommand(UINT code, LPARAM /* param */, LRESULT &result)
{
	result = FALSE;
	switch (code)
	{
		case CBN_DROPDOWN:
		{
			ComboBoxPaths.clear();
			_headerComboBox.ResetContent();

			size_t i;
			CStringVector pathParts;

			FileSystem::SplitPathToParts(m_directory.GetCurrentDirectory(), pathParts);
			CString sumPass;
			if (!pathParts.empty())
			{
				pathParts.pop_back();
			}
			for (i = 0; i < pathParts.size(); i++)
			{
				CString name = pathParts[i];
				sumPass += name;
				sumPass += CHAR_PATH_SEPARATOR;
				FileSystem::File::CFileInfo info;
				DWORD attrib = FILE_ATTRIBUTE_DIRECTORY;
				if (info.Find(sumPass))
				{
					attrib = info.Attributes;
				}
				AddComboBoxItem(name.IsEmpty() ? _T("\\") : name,  FileManager::FileSystem::GetRealIconIndex(sumPass, attrib), i, false);
				ComboBoxPaths.push_back(sumPass);
			}

#ifndef UNDER_CE

			int iconIndex;
			CString name;
			name = FileSystem::RootFolder_GetName_Documents(iconIndex);
			AddComboBoxItem(name, iconIndex, 0, true);

			name = FileSystem::RootFolder_GetName_Computer(iconIndex);
			AddComboBoxItem(name, iconIndex, 0, true);

			CStringVector driveStrings;
			FileSystem::Find::MyGetLogicalDriveStrings(driveStrings);
			for (i = 0; i < driveStrings.size(); i++)
			{
				CString s = driveStrings[i];
				ComboBoxPaths.push_back(s);
				int iconIndex = FileManager::FileSystem::GetRealIconIndex(s, 0);
				if (s.GetLength() > 0 && s[s.GetLength() - 1] == CHAR_PATH_SEPARATOR)
				{
					s.Delete(s.GetLength() - 1);
				}
				AddComboBoxItem(s, iconIndex, 1, false);
			}

			name = FileSystem::RootFolder_GetName_Network(iconIndex);
			AddComboBoxItem(name, iconIndex, 0, true);

#endif

			return false;
		}

		case CBN_SELENDOK:
		{
			code = code;
			int index = _headerComboBox.GetCurSel();
			if (index >= 0)
			{
				CString pass = ComboBoxPaths[index];
				_headerComboBox.SetCurSel(-1);
				// _headerComboBox.SetText(pass); // it's fix for seclecting by mouse.
				if (m_directory.BindToPathAndRefresh(pass) == S_OK)
				{
					RefreshListCtrl();
					PostMessage(kSetFocusToListView);
#ifdef UNDER_CE
					PostMessage(kRefreshHeaderComboBox);
#endif

					return true;
				}
			}
			return false;
		}
	}
	return false;
}

bool CPanel::OnNotifyComboBox(LPNMHDR header, LRESULT &result, BOOL &bHandled)
{
#ifndef UNDER_CE
	switch (header->code)
	{
		case CBEN_BEGINEDIT:
		{
			_lastFocusedIsList = false;
			break;
		}
		case CBEN_ENDEDIT:
		{
			return OnNotifyComboBoxEndEdit((PNMCBEENDEDITW)header, result);
		}
		bHandled = FALSE;
	}
#endif
	return false;
}


void CPanel::FoldersHistory()
{
	CListViewDialog listViewDialog;
	listViewDialog.DeleteIsAllowed = true;
	listViewDialog.Title = Lang::LangString(IDS_FOLDERS_HISTORY, 0x03020260);
	_appState->FolderHistory.GetList(listViewDialog.Strings);
	if (listViewDialog.DoModal() == IDCANCEL)
	{
		return;
	}
	CString selectString;
	if (listViewDialog.StringsWereChanged)
	{
		_appState->FolderHistory.RemoveAll();
		for (auto it = listViewDialog.Strings.rbegin(); it != listViewDialog.Strings.rend(); ++it)
		{
			_appState->FolderHistory.AddString(*it);
		}
		if (listViewDialog.FocusedItemIndex >= 0)
		{
			selectString = listViewDialog.Strings[listViewDialog.FocusedItemIndex];
		}
	}
	else
	{
		if (listViewDialog.FocusedItemIndex >= 0)
		{
			selectString = listViewDialog.Strings[listViewDialog.FocusedItemIndex];
		}
	}
	if (listViewDialog.FocusedItemIndex >= 0)
	{
		m_directory.BindToPathAndRefresh(selectString);
		RefreshListCtrl();
	}
}

//moved from DirectoryOperations.cpp/PanelOperations.cpp

void CPanel::DeleteItems(bool toRecycleBin)
{
	std::vector<UINT32> indices;
	GetOperatedItemIndices(indices);
	if (indices.empty())
	{
		return;
	}
	CSelectedState state;
	SaveSelectedState(state);
	m_directory.DeleteItems(indices, toRecycleBin);
	RefreshListCtrl(state);
	RefreshTitleAlways();
}


BOOL CPanel::OnBeginLabelEdit(LV_DISPINFOW* lpnmh)
{
	int realIndex = GetRealIndex(lpnmh->item);
	if (FileManager::FileSystem::kParentIndex == realIndex )
	{
		return TRUE;
	}
	if (!m_directory.DoesItSupportOperations())
	{
		return TRUE;
	}
	return FALSE;
}

BOOL CPanel::OnEndLabelEdit(LV_DISPINFOW* lpnmh)
{
	if (lpnmh->item.pszText == NULL)
	{
		return FALSE;
	}

	const CString newName = lpnmh->item.pszText;

	SaveSelectedState(_selectedState);

	int realIndex = GetRealIndex(lpnmh->item);
	if (FileManager::FileSystem::kParentIndex == realIndex)
	{
		return FALSE;
	}

	if (m_directory.EditName(realIndex, newName))
	{
		// Can't use RefreshListCtrl here.
		// RefreshListCtrlSaveFocused();
		_selectedState.FocusedName = m_directory.GetItemPrefix(realIndex) + newName;
		_selectedState.SelectFocused = true;

		// We need clear all items to disable GetText before Reload:
		// number of items can change.
		// _listView.DeleteAllItems();
		// But seems it can still call GetText (maybe for current item)
		// so we can't delete items.

		_dontShowMode = true;

		PostMessage(kReLoadMessage);
		return TRUE;
	}
	return FALSE;
}

void CPanel::CreateFolder()
{
	CSelectedState state;
	SaveSelectedState(state);
	CString newName;
	if (m_directory.CreateFolder(newName))
	{
		if (!_mySelectMode)
		{
			state.SelectedNames.clear();
		}
		state.FocusedName = newName;
		state.SelectFocused = true;
		RefreshTitleAlways();
		RefreshListCtrl(state);
	}

}

void CPanel::CreateFile()
{
	CSelectedState state;
	SaveSelectedState(state);
	CString newName;
	if (m_directory.CreateFile(newName))
	{
		if (!_mySelectMode)
		{
			state.SelectedNames.clear();
		}
		state.FocusedName = newName;
		state.SelectFocused = true;
		RefreshListCtrl(state);
	}
}



void CPanel::ChangeComment()
{
	CDisableTimerProcessing disableTimerProcessing2(*this);
	int index = _listView.GetNextItem(-1, LVNI_FOCUSED);
	if (index < 0)
	{
		return;
	}

	CSelectedState state;
	SaveSelectedState(state);

	if(m_directory.ChangeComment(index))
	{
		RefreshListCtrl(state);
	}
}

//from DirectoryCopy.cpp/PanelCopy.cpp
void CPanel::CopyFromNoAsk(const CStringVector &filePaths)
{

	CSelectedState srcSelState;
	SaveSelectedState(srcSelState);

	HRESULT result = m_directory.CopyFrom(_T(""), filePaths, true, 0);

	if (result != S_OK)
	{
		// For Password:
		SetFocusToList();
		if (result != E_ABORT)
		{
			FileManager::CWindows::MessageBoxError(*this, result);
		}
		return;
	}

	RefreshListCtrl(srcSelState);

	SetFocusToList();
}

void CPanel::CopyFromAsk(const CStringVector &filePaths)
{
	CString title = Lang::LangString(IDS_CONFIRM_FILE_COPY, 0x03020222);
	CString message = Lang::LangString(IDS_WANT_TO_COPY_FILES, 0x03020223);
	message += _T("\n\'");
	message += m_directory.GetCurrentDirectory();
	message += _T("\' ?");
	int res = ::MessageBox(*this, message, title, MB_YESNOCANCEL | MB_ICONQUESTION);
	if (res != IDYES)
	{
		return;
	}

	CopyFromNoAsk(filePaths);
}


void CPanel::OpenFolder(int index)
{
	m_directory.OpenFolder(index);
	RefreshListCtrl();
	UINT state = LVIS_SELECTED;
	_listView.SetItemState(_listView.GetNextItem(-1, LVNI_FOCUSED), state, state);
	_listView.EnsureVisible(_listView.GetNextItem(-1, LVNI_FOCUSED), false);
}

//taken from App.cpp
//TODO: Check if needed
//void CPanel::OnCopy(bool move, bool copyToSame)
void CPanel::CopyItems(bool move, bool copyToSame)
{

	CPanel::CDisableTimerProcessing disableTimerProcessing1(*this);

	if (!m_directory.DoesItSupportOperations())
	{
		FileManager::CWindows::MessageBoxErrorLang(*this, IDS_OPERATION_IS_NOT_SUPPORTED, 0x03020208);
		return;
	}

	std::vector<UINT32> indices;
	CString destPath;
	bool useDestPanel = false;

	{
		if (copyToSame)
		{
			int focusedItem = _listView.GetNextItem(-1, LVNI_FOCUSED);
			if (focusedItem < 0)
			{
				return;
			}
			int realIndex = GetRealItemIndex(focusedItem);
			if (realIndex == FileManager::FileSystem::kParentIndex)
			{
				return;
			}
			indices.push_back(realIndex);
			destPath = m_directory.GetItemName(realIndex);
		}
		else
		{
			GetOperatedIndicesSmart(indices);
			if (indices.size() == 0)
			{
				return;
			}
			destPath = m_directory.GetCurrentDirectory();
			FileManager::FileSystem::ReducePathToRealFileSystemPath(destPath);
		}

		CCopyDialog copyDialog;
		CStringVector copyFolders;
		ReadCopyHistory(copyFolders);

		copyDialog.Strings = copyFolders;
		copyDialog.Value = destPath;

		copyDialog.Title = move ?
			Lang::LangString(IDS_MOVE, 0x03020202) :
			Lang::LangString(IDS_COPY, 0x03020201);
		copyDialog.Static = move ?
			Lang::LangString(IDS_MOVE_TO, 0x03020204) :
			Lang::LangString(IDS_COPY_TO, 0x03020203);

		copyDialog.Info = m_directory.GetItemsInfoString(indices);

		if (copyDialog.DoModal() == IDCANCEL)
		{
			return;
		}

		destPath = copyDialog.Value;

		if (destPath.IsEmpty())
		{
			FileManager::CWindows::MessageBoxErrorLang(*this, IDS_OPERATION_IS_NOT_SUPPORTED, 0x03020208);
			return;
		}

		if (!FileManager::FileSystem::IsPathAbsolute(destPath))
		{
			if (!m_directory.IsFSFolder())
			{
				FileManager::CWindows::MessageBoxErrorLang(*this, IDS_OPERATION_IS_NOT_SUPPORTED, 0x03020208);
				return;
			}
			destPath = m_directory.GetCurrentDirectory() + destPath;
		}

#ifndef UNDER_CE
		if (destPath.GetLength() > 0 && destPath[0] == '\\')
		if (destPath.GetLength() == 1 || destPath[1] != '\\')
		{
			FileManager::CWindows::MessageBoxErrorLang(*this, IDS_OPERATION_IS_NOT_SUPPORTED, 0x03020208);
			return;
		}
#endif

		if (indices.size() > 1 ||
			(!destPath.IsEmpty() && destPath.Left(destPath.GetLength() - 1) == CHAR_PATH_SEPARATOR) ||
			FileSystem::Find::DoesDirExist(destPath) ||
			m_directory.IsArcFolder())
		{
			FileSystem::CreateComplexDirectory(destPath);
			FileSystem::FileName::NormalizeDirPathPrefix(destPath);
			if (!FileManager::FileSystem::CheckFolderPath(destPath))
			{
				if (destPath != m_directory.GetCurrentDirectory() || !m_directory.DoesItSupportOperations())
				{
					FileManager::CWindows::MessageBoxErrorLang(*this, IDS_OPERATION_IS_NOT_SUPPORTED, 0x03020208);
					return;
				}
			}
		}
		else
		{
			int pos = destPath.ReverseFind(CHAR_PATH_SEPARATOR);
			if (pos >= 0)
			{
				CString prefix = destPath.Left(pos + 1);
				FileSystem::CreateComplexDirectory(prefix);
				if (!FileManager::FileSystem::CheckFolderPath(prefix))
				{
					FileManager::CWindows::MessageBoxErrorLang(*this, IDS_OPERATION_IS_NOT_SUPPORTED, 0x03020208);
					return;
				}
			}
		}

		AddUniqueStringToHeadOfList(copyFolders, destPath);
		while (copyFolders.size() > 20)
		{
			copyFolders.pop_back();
		}
		SaveCopyHistory(copyFolders);
	}


	bool useSrcPanel = (!useDestPanel || !m_directory.IsFsOrDrivesFolder() || m_directory.IsFSFolder());
	bool useTemp = useSrcPanel && useDestPanel;
	Common::FileSystem::CTempDirectory tempDirectory;
	CString tempDirPrefix;
	if (useTemp)
	{
		tempDirectory.Create(FileManager::FileSystem::kTempDirPrefix);
		tempDirPrefix = tempDirectory.GetPath();
		FileSystem::FileName::NormalizeDirPathPrefix(tempDirPrefix);
	}

	CSelectedState srcSelState;
	CSelectedState destSelState;
	SaveSelectedState(srcSelState);
	SaveSelectedState(destSelState);

	HRESULT result;
	if (useSrcPanel)
	{
		CString folder = useTemp ? tempDirPrefix : destPath;
		result = m_directory.CopyTo(indices, folder, move, true, 0);
		if (result != S_OK)
		{
			disableTimerProcessing1.Restore();
			// For Password:
			SetFocusToList();
			if (result != E_ABORT)
			{
				FileManager::CWindows::MessageBoxError(*this, result, _T("Error"));
			}
			return;
		}
		RefreshTitleAlways();
	}

	if (useDestPanel)
	{
		CStringVector filePaths;
		CString folderPrefix;
		if (useTemp)
		{
			folderPrefix = tempDirPrefix;
		}
		else
		{
			folderPrefix = m_directory.GetCurrentDirectory();
		}
		//filePaths.Reserve(indices.Size());
		for (size_t i = 0; i < indices.size(); i++)
		{
			filePaths.push_back(m_directory.GetItemRelPath(indices[i]));
		}

		result = m_directory.CopyFrom(folderPrefix, filePaths, true, 0);

		if (result != S_OK)
		{
			disableTimerProcessing1.Restore();
			// For Password:
			SetFocusToList();
			if (result != E_ABORT)
			{
				FileManager::CWindows::MessageBoxError(*this, result, _T("Error"));
			}
			return;
		}
		RefreshTitleAlways();
	}

	RefreshTitleAlways();
	if (copyToSame || move)
	{
		RefreshListCtrl(srcSelState);
	}
	if (!copyToSame)
	{
		RefreshListCtrl(destSelState);
		KillSelection();
	}
	disableTimerProcessing1.Restore();
	SetFocusToList();
}

//new functions
void CPanel::SplitSelectedFiles()
{
	std::vector<UINT32> indices;
	GetOperatedItemIndices(indices);
	m_directory.SplitFiles(indices);
	RefreshTitleAlways();
}

void CPanel::CombineSelectedFiles()
{
	std::vector<UINT32> indices;
	GetOperatedItemIndices(indices);
	m_directory.CombineFiles(indices);
	RefreshTitleAlways();
}